package com.example.myapplication.function.musicmode

import android.util.Log

/**
 * 2. 音高检测模块（使用自相关算法）
 */
class PitchDetector {
    companion object {
        private const val SAMPLE_RATE = 44100
        private const val MIN_FREQUENCY = 80.0
        private const val MAX_FREQUENCY = 1000.0

        // 完整的音符频率表 (C0 ~ B8)
        val NOTE_FREQUENCIES = mapOf(
            // 第4八度 (中央C附近)
            "C4" to 261.63, "C#4" to 277.18, "D4" to 293.66, "D#4" to 311.13,
            "E4" to 329.63, "F4" to 349.23, "F#4" to 369.99, "G4" to 392.00,
            "G#4" to 415.30, "A4" to 440.00, "A#4" to 466.16, "B4" to 493.88,
            // 第5八度
            "C5" to 523.25, "C#5" to 554.37, "D5" to 587.33, "D#5" to 622.25,
            "E5" to 659.25, "F5" to 698.46, "F#5" to 739.99, "G5" to 783.99,
            "G#5" to 830.61, "A5" to 880.00, "A#5" to 932.33, "B5" to 987.77,
            // 第3八度
            "C3" to 130.81, "C#3" to 138.59, "D3" to 146.83, "D#3" to 155.56,
            "E3" to 164.81, "F3" to 174.61, "F#3" to 185.00, "G3" to 196.00,
            "G#3" to 207.65, "A3" to 220.00, "A#3" to 233.08, "B3" to 246.94
        )

        // 音高置信度阈值
        private const val CONFIDENCE_THRESHOLD = 0.3
    }

    /**
     * 使用改进的自相关算法检测音高
     */
    fun detectPitch(audioData: FloatArray): Double? {
        if (audioData.size < 1024) {
            Log.w("PitchDetector", "Audio data too short: ${audioData.size}")
            return null
        }

        try {
            val data = audioData.copyOf()

            // 1. 预处理：应用窗函数
            applyHanningWindow(data)

            // 2. 计算自相关函数
            val correlation = calculateAutocorrelation(data)

            // 3. 寻找基频峰值
            val fundamentalFrequency = findFundamentalFrequency(correlation)

            // 4. 验证频率范围
            return if (fundamentalFrequency in MIN_FREQUENCY..MAX_FREQUENCY) {
                fundamentalFrequency
            } else {
                null
            }
        } catch (e: Exception) {
            Log.e("PitchDetector", "Error in pitch detection", e)
            return null
        }
    }

    private fun applyHanningWindow(data: FloatArray) {
        for (i in data.indices) {
            val multiplier = 0.5 * (1 - Math.cos(2.0 * Math.PI * i / (data.size - 1)))
            data[i] = (data[i] * multiplier).toFloat()
        }
    }

    private fun calculateAutocorrelation(data: FloatArray): FloatArray {
        val n = data.size
        val correlation = FloatArray(n / 2)

        for (lag in correlation.indices) {
            var sum = 0.0f
            for (i in 0 until n - lag) {
                sum += data[i] * data[i + lag]
            }
            correlation[lag] = sum / (n - lag) // 归一化
        }
        return correlation
    }

    private fun findFundamentalFrequency(correlation: FloatArray): Double {
        // 定义合理的滞后范围（对应MIN_FREQUENCY ~ MAX_FREQUENCY）
        val minLag = (SAMPLE_RATE / MAX_FREQUENCY).toInt()
        val maxLag = (SAMPLE_RATE / MIN_FREQUENCY).toInt()

        var maxIndex = minLag
        var maxValue = correlation[minLag]

        // 在合理范围内寻找第一个显著峰值
        for (i in minLag + 1 until minOf(maxLag, correlation.size)) {
            if (correlation[i] > maxValue) {
                maxValue = correlation[i]
                maxIndex = i
            }
        }

        // 二次插值提高精度
        val preciseIndex = parabolicInterpolation(correlation, maxIndex)
        return SAMPLE_RATE.toDouble() / preciseIndex
    }

    private fun parabolicInterpolation(correlation: FloatArray, index: Int): Double {
        if (index <= 0 || index >= correlation.size - 1) {
            return index.toDouble()
        }

        val alpha = correlation[index - 1]
        val beta = correlation[index]
        val gamma = correlation[index + 1]

        val denominator = alpha - 2 * beta + gamma
        if (Math.abs(denominator) < 1e-10) {
            return index.toDouble()
        }

        val delta = (alpha - gamma) / (2.0f * denominator)
        return index.toDouble() + delta
    }

    /**
     * 将频率转换为最接近的音符
     */
    fun frequencyToNote(frequency: Double): String {
        // 计算距离A4的半音数
        val semitonesFromA4 = 12 * Math.log(frequency / 440.0) / Math.log(2.0)
        val roundedSemitones = Math.round(semitonesFromA4).toInt()

        // 计算音符索引和八度
        val noteIndex = (roundedSemitones + 69) % 12
        val octave = (roundedSemitones + 69) / 12

        val noteNames = arrayOf("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
        val noteName = noteNames[noteIndex]

        return "$noteName$octave"
    }

    /**
     * 计算检测准确度 (0.0 ~ 1.0)
     */
    fun calculateAccuracy(frequency: Double, targetNote: String): Double {
        val targetFreq = NOTE_FREQUENCIES[targetNote] ?: return 0.0

        // 计算频率比值的音分差
        val centsDifference = 1200 * Math.log(frequency / targetFreq) / Math.log(2.0)

        // 音分差越小，准确度越高
        val maxCentsDifference = 50.0 // 允许最大50音分偏差
        val accuracy = 1.0 - Math.min(Math.abs(centsDifference) / maxCentsDifference, 1.0)

        return Math.max(0.0, accuracy)
    }

    /**
     * 批量处理音频数据，返回音高列表
     */
    fun detectPitches(audioDataList: List<FloatArray>): List<Double> {
        return audioDataList.mapNotNull { detectPitch(it) }
    }

    /**
     * 获取当前音频数据的能量（用于静音检测）
     */
    fun calculateEnergy(audioData: FloatArray): Double {
        var sum = 0.0
        for (sample in audioData) {
            sum += sample * sample
        }
        return sum / audioData.size
    }

}